package com.raymond.smgp.utils;

import org.apache.commons.codec.DecoderException;
import org.apache.commons.codec.binary.Hex;

import java.util.*;

/**
 * SMGP消息id算法
 *
 *
 *
 * @author :  raymond
 * @version :  V1.0
 * @date :  2021-04-28 11:39
 */
public class SmgpMsgId {

    private volatile String time;

    private String lastTime;

    private String gatewayCode;

    private long sequence;


    private static SmgpMsgId smgpMsgId = null;

    public static SmgpMsgId getInstance() {
        return getInstance("012345");
    }

    public static SmgpMsgId getInstance(String gatewayCode) {
        if (smgpMsgId == null) {
            synchronized (SmgpMsgId.class) {
                if (smgpMsgId == null) {
                    smgpMsgId = new SmgpMsgId(gatewayCode);
                }
            }
        }
        if (!gatewayCode.equals(smgpMsgId.gatewayCode)) {
            throw new IllegalArgumentException(
                    String.format("worker Id Don't agree, The existing %d, The current %d", Long.parseLong(smgpMsgId.gatewayCode), Long.parseLong(gatewayCode)));
        }
        return smgpMsgId;
    }

    public synchronized String nextId() {
        String now = getTime(System.currentTimeMillis());
        if (now.equals(this.time)) {
            /**序号最大值**/
            int maxSequence = 999999;
            if (++sequence > maxSequence) {
                this.lastTime = tilNextMillis();
                sequence = 0;
            }
        } else {
            this.lastTime = tilNextMillis();
            sequence = 0;
        }
        return gatewayCode + lastTime + String.format("%06d", sequence);
    }

    public long pkNoMsgId(long msgId, long pkNo) {
        return msgId | (pkNo << 34);
    }

    private String tilNextMillis() {
        String timestamp = getTime(System.currentTimeMillis());
        while (timestamp.equals(this.time)) {
            this.time = getTime(System.currentTimeMillis());
        }
        this.time = getTime(System.currentTimeMillis());
        return getTime(System.currentTimeMillis());
    }

    private String getTime(long time) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTimeInMillis(time);
        long month = calendar.get(Calendar.MONTH) + 1;
        long day = calendar.get(Calendar.DAY_OF_MONTH);
        long hour = calendar.get(Calendar.HOUR_OF_DAY);
        long min = calendar.get(Calendar.MINUTE);
        return String.format("%02d", month) + String.format("%02d", day) + String.format("%02d", hour) + String.format("%02d", min);
    }

    private SmgpMsgId(String gatewayCode) {
        // 检查机房id和工作机器id是否超过31 不能小于0
//        if (gatewayCode > maxGatewayCode || gatewayCode < 0) {
//            throw new IllegalArgumentException(
//                    String.format("worker Id can't be greater than %d or less than 0", gatewayCode));
//        }
        this.gatewayCode = gatewayCode;
        this.time = getTime(System.currentTimeMillis());
        this.lastTime = getTime(System.currentTimeMillis());
    }

    /**
     * 通过平台流水号获取流水号信息
     * @param ptMsgId 平台流水号
     * @return 流水号信息
     */
    public static String getYmd(long ptMsgId) {
        int year = Calendar.getInstance().get(Calendar.YEAR);
        int month = Calendar.getInstance().get(Calendar.MONTH) + 1;
        long mon = (ptMsgId >> 60) & 15;
        if (mon == 12 && month == 1) {
            year --;
        }
        long day = (ptMsgId >> 55) & 31;
        return year + "年" + String.format("%02d", mon) + "月" + String.format("%02d", day) +
                "日" + ((ptMsgId >> 50) & 63) + "时" + ((ptMsgId >> 44) & 63) + "分" + ((ptMsgId >> 38) & 63) + "秒" +
                ",第" + (((ptMsgId >> 34) & 15) + 1)+ "条" + ",网关编码:" + ((ptMsgId >> 24) & 1023) + ",序列号:" + (ptMsgId & 16777215);
    }

    public static void main(String[] args) throws InterruptedException, DecoderException {
        SmgpMsgId cmppMsgId = SmgpMsgId.getInstance("012345");
//        Thread.sleep(2000);
        int count = 1 << 5;
        System.out.println("kaishi ");
        List<String> list = new ArrayList<>();
        long start = System.currentTimeMillis();
        for (int i = 0; i < count; i++) {
            list.add(cmppMsgId.nextId());
            String s = cmppMsgId.nextId();
            System.out.println(s);
            System.out.println(Arrays.toString(Hex.decodeHex(s)));
        }
        System.out.println("耗时:" + (System.currentTimeMillis() - start));
        System.out.println("总数:" + list.size());
        Set<String> set = new HashSet<>(list);
        System.out.println("去重总数:" + set.size());
        System.out.println(getYmd(2027443091681574913L));
        start = System.currentTimeMillis();
        System.out.println(Integer.parseInt(String.format("%tm", start)));
        System.out.println(Integer.parseInt(String.format("%td", start)));
        System.out.println(Integer.parseInt(String.format("%tH", start)));
        System.out.println(Integer.parseInt(String.format("%tM", start)));
        System.out.println(Integer.parseInt(String.format("%tS", start)));
    }
}
